package com.sikaryofficial.backend.controller;

import cn.hutool.core.util.ReflectUtil;
import com.sikaryofficial.backend.annotation.ReloadActionDataCache;
import com.sikaryofficial.backend.annotation.Repeat;
import com.sikaryofficial.backend.config.MyStatisticsClosedConfig;
import com.sikaryofficial.backend.domain.dto.req.BrandSpecialStatisticsReq;
import com.sikaryofficial.backend.domain.dto.req.OtherStatisticsReq;
import com.sikaryofficial.backend.domain.dto.resp.MyBalanceDTO;
import com.sikaryofficial.backend.domain.vo.BrandSpecialStatisticsVO;
import com.sikaryofficial.backend.domain.vo.MyStatisticsVO;
import com.sikaryofficial.backend.domain.vo.OtherStatisticsVO;
import com.sikaryofficial.backend.manager.MyStatisticsManager;
import com.sikaryofficial.common.core.domain.R;
import com.sikaryofficial.common.core.web.controller.BaseController;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import com.sikaryofficial.system.api.model.infomation.MyStatisticsClosedVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;

/**
 * 我的统计Controller
 *
 * @author qinjinyuan
 * @date 2023-11-06
 */
@RestController
@RequestMapping("/myStatistics")
@Api(tags = "我的-个人中心")
public class MyStatisticsController extends BaseController {
    /**
     * 统计开关字段名称
     */
    private static final String OPEN_METHOD_NAME = "setHasOpen";
    @Autowired
    private MyStatisticsManager myStatisticsManager;
    @Resource
    private MyStatisticsClosedConfig config;

    /**
     * 获取【我的】相关统计数据
     */
    @GetMapping("/my")
    @ApiOperation("获取【我的】相关统计数据")
    public R<MyStatisticsVO> myStatistics() {
        MyStatisticsVO result = myStatisticsManager.getMyStatistics(SecurityUtils.getUserId());
        applyOpenSettings(result, config);
        return R.ok(result);
    }

    /**
     * 获取【我的】相关统计数据
     */
    @PostMapping("/other")
    @ApiOperation("获取【他人的】相关统计数据")
    @Repeat
    public R<OtherStatisticsVO> otherStatistics(@Validated @RequestBody OtherStatisticsReq req) {
        OtherStatisticsVO result = myStatisticsManager.otherStatistics(req.getUserId());
        applyOpenSettings(result, config);
        return R.ok(result);
    }

    /**
     * 获取【品牌专栏】相关统计数据
     */
    @PostMapping("/brandSpecial")
    @ApiOperation("V2.5 获取【品牌专栏】相关统计数据")
    @Repeat
    public R<BrandSpecialStatisticsVO> brandSpecialStatistics(@Validated @RequestBody BrandSpecialStatisticsReq req) {
        return R.ok(myStatisticsManager.brandSpecialStatistics(req));
    }

    /**
     * 获取【我的】个人积分及个人图片和背景图
     */
    @GetMapping("/myBalance")
    @ApiOperation("个人积分及个人图片和背景图")
    @ReloadActionDataCache
    public R<MyBalanceDTO> myBalance() {
        return R.ok(myStatisticsManager.getMyBalance());
    }

    /**
     * 获取【他人的】个人积分及个人图片和背景图
     */
    @PostMapping("/otherBalance")
    @ApiOperation("他人积分及图片和背景图")
    @Repeat
    public R<MyBalanceDTO> otherBalance(@Validated @RequestBody OtherStatisticsReq req) {
        return R.ok(myStatisticsManager.otherBalance(req.getUserId()));
    }

    /**
     * 根据配置进行开关设置
     *
     * @param result
     * @param config
     */
    private void applyOpenSettings(Object result, MyStatisticsClosedConfig config) {
        Class<?> clazz = result.getClass();
        Field[] fields = ReflectUtil.getFields(clazz);
        for (Field field : fields) {
            Object fieldValue = ReflectUtil.getFieldValue(result, field.getName());
            if (!config.checkFiledNameExist(field.getName()) || Objects.isNull(fieldValue)) {
                continue;
            }
            Optional<Method> openMethodOpt = Arrays.stream(ReflectUtil.getMethods(fieldValue.getClass()))
                    .filter(method -> method.getName().equals(OPEN_METHOD_NAME))
                    .findFirst();
            openMethodOpt.ifPresent(method -> {
                MyStatisticsClosedVO myStatisticsClosedVO = config.getByFiledName(field.getName());
                ReflectUtil.invoke(fieldValue, method.getName(), myStatisticsClosedVO.isHasOpen());
            });
        }
    }
}
